package sf.model;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Vector;

import javax.swing.SwingWorker;
import javax.swing.table.DefaultTableModel;

import sf.view.StandardForm;
import sf.view.StatusBar;

public class SQLTableModel extends DefaultTableModel {

	private static final long serialVersionUID = 1L;

	private Context context;
	private StatusBar statusBar;

	private ResultSetMetaData metaData;
	private List<DBColumnInfo> columns;

	@SuppressWarnings("unchecked")
	public SQLTableModel(Context context, StatusBar statusBar) {
		this.context = context;
		this.statusBar = statusBar;

		int mode = context.getMode();
		
    	if ((mode & StandardForm.FROM_MENU) != 0)
			initData((mode & StandardForm.MODE_SEARCH) == 0);
		else if ((mode & StandardForm.FROM_NEXT) != 0)
			filter((HashMap<String, Object>) context.getParam("filter"));
		else if ((mode & StandardForm.FROM_ZOOM) != 0)
			filter((HashMap<String, Object>) context.getParam("filter"));
	}

	private void initData(boolean fillTable) {
		ResultSet rs = DBManager.getResultSet();

		try {
			metaData = rs.getMetaData();

			columns = DBTableInfo.getColumns(context.getTable().toUpperCase(),
					metaData);

			setColumnCount(metaData.getColumnCount());

			if (fillTable)
				new TableDataInit(rs).execute();
		} catch (SQLException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}

	private class TableDataInit extends SwingWorker<Void, Vector<Object>> {
		private ResultSet rs;

		public TableDataInit(ResultSet rs) {
			this.rs = rs;

			addPropertyChangeListener(new PropertyChangeListener() {
				public void propertyChange(PropertyChangeEvent evt) {
					String prop = evt.getPropertyName();
					Object value = evt.getNewValue();
					if (prop.equals("state")) {
						if (value.toString().equals("STARTED")) {
							statusBar.showProgressBar(true);
						} else if (value.toString().equals("DONE")) {
							statusBar.showProgressBar(false);
						}
					}
				}
			});
		}

		@SuppressWarnings("unchecked")
		protected Void doInBackground() throws Exception {
			while (rs.next()) {
				Vector<Object> row = new Vector<Object>();
				for (int i = 1; i < getColumnCount() + 1; i++)
					row.addElement(rs.getObject(i));
				// Thread.sleep(100);
				publish(row);
			}

			return null;
		}

		protected void process(List<Vector<Object>> rows) {
			for (Vector<Object> row : rows)
				addRow(row);
		}

		protected void done() {
			fireTableDataChanged();
		}
	}

	public boolean addNewRow(LinkedHashMap<String, Object> values) {
		boolean success = false;
		if (DBManager.insert(values)) {
			Vector<Object> row = new Vector<Object>();
			for (Object value : values.values())
				row.addElement(value);
			addRow(row);
			fireTableDataChanged();
			success = true;
		}
		
		return success;
	}

	public boolean updateRow(LinkedHashMap<String, Object> values, int row) {
		boolean success = false;
		if (DBManager.update(values)) {
			int column = 0;
			for (Object value : values.values())
				setValueAt(value, row, column++);
			fireTableDataChanged();
			success = true;
		}
		
		return success;
	}

	public boolean deleteRow(LinkedHashMap<String, Object> values, int row) {
		boolean success = false;
		if (DBManager.delete(values)) {
			removeRow(row);
			fireTableDataChanged();
			success = true;
		}
		
		return success;
	}

	public boolean filter(HashMap<String, Object> values) {
		boolean success = false;
		if (DBManager.filter(values)) {
			getDataVector().clear();
			initData(true);
			success = true;
		}
		
		return success;
	}

	public String getColumnName(int index) {
		return columns.get(index).getLabel();
	}

	public String getColumnCode(int index) {
		return columns.get(index).getCode();
	}

	public void refresh() {
		if (DBManager.disableFilter()) {
			getDataVector().clear();
			initData(true);
		}
	}

	public int getColumnSize(int index) {
		return columns.get(index).getSize();
	}

	public Class<?> getColumnClass(int index) {
		return columns.get(index).getCls();
	}

	public boolean isCellEditable(int rowIndex, int columnIndex) {
		return false;
	}

	public List<DBColumnInfo> getColumns() {
		return columns;
	}
}
